;;;;;;;;;;
;; Start the server. If a server is already running, the server is not started.
(if window-system
    (server-start))

;; Load modes supplied by Emacs standard distribution
(require 'etags)
(require 'thingatpt)
(require 'ido)
(require 'dired)
(require 'whitespace)


;;;;;;;;;;
;; Append additional directories to load-path and load required libraries.
(setq load-path (append
                 '("~/.emacs.d"
                   "~/.emacs.d/modes")
                 load-path))

(defgroup my-customs nil
  "Customizing group of init.el. It offers an easy way to keep
the init file as it is and to adapt certain variables depedent on
the actual work station or project your are working on.

Here is a additional tip to customize Emacs for your project
needs, this variables might be useful:

    * `ff-search-directories'
    * `compilation-search-path'
    * `grep-find-template'
    * `grep-find-ignored-directories'
    * `grep-find-ignored-files'

They are part of Emacs standard packages and does not belong to
init.el."
  :group 'tools)

(setq custom-file "~/.emacs.d/custom.el")
(load custom-file 'noerror)


;;;;;;;;;;
;; The history mode
(setq savehist-additional-variables    ;; also save...
      '(search-ring regexp-search-ring)    ;; ... my search entries
      savehist-file "~/.emacs.d/savehist") ;; keep my home clean
(savehist-mode t)                      ;; do customization before activate


(if window-system
    (progn
      ;; load a nice color theme
      (enable-theme 'themes/dark-ink)
      ;; When running in a windowed mode the mouse pointer shouldn't
      ;; interfere with the cursor.
      (mouse-avoidance-mode 'cat-and-mouse)))

;;;;;;;;;;
;; Set up defaults for the Latin-1 character set which supports most of
;; the languages of Western Europe.
(set-language-environment "UTF-8")

;; Set the frame's title. %b is the name of the buffer. %+ indicates
;; the state of the buffer: * if modified, % if read only, or -
;; otherwise. Two of them to emulate the mode line. %f for the file
;; name. Incredibly useful!
(setq-default frame-title-format
              '(:eval
                (format "%s (%s)"
                        (buffer-name)
                        (file-name-directory (or (buffer-file-name)
                                                 default-directory)))))



;; Remove default key bindings to use them for my own bindings. As a mnemonic
;; trick, C-f stand for 'find' nd 'C-b' for 'build' or 'begin'.
(global-unset-key (kbd "C-f"))
(global-unset-key (kbd "C-b"))


;;;;;;;;;;
;; A quick access key for my-customs
(global-set-key (kbd "C-b !") '(lambda ()
                                 (interactive)
                                 (customize-group 'my-customs)))

;;;;;;;;;;
;; Some customizing and search path adjustments dependent on the actual system
;; type.
(cond
 ((eq system-type 'windows-nt)
  (setq exec-path (append '("c:/cygwin/usr/local/bin" "c:/cygwin/bin") exec-path))
  (setenv "PATH" (concat "c:\\cygwin\\usr\\local\\bin;" "c:\\cygwin\\bin;" (getenv "PATH"))))
 ((eq system-type 'darwin)
  (setq exec-path (append '("/usr/local/bin") exec-path))
  (setenv "PATH" (concat "/usr/local/bin:" (getenv "PATH")))))


;;;;;;;;;;
;;  Find-file: Some rules how to find matching files.
(eval-after-load "find-file"
  '(setq-default ff-other-file-alist '(("\\.m$" (".h"))
                                       ("\\.c$" (".h"))
                                       ("\\.h$" (".c" ".m"))
                                       ("\\.hpp$" (".cpp" ".c")))))

(global-set-key (kbd "C-f <tab>") 'ff-find-other-file)


;;;;;;;;;;
;; My Ediff configuration.
;; Find out more on http://www.emacswiki.org/emacs/EdiffMode
(eval-after-load "ediff"
  (progn (setq ediff-window-setup-function 'ediff-setup-windows-plain)
         (setq ediff-split-window-function 'split-window-horizontally)
         (setq-default ediff-ignore-similar-regions t)))


;;;;;;;;;;
;; Grep
;; To maximize speed of a grep command, don't forget to customize
;; grep-find-ignored-directories and grep-find-ignored-files.
(global-set-key (kbd "C-f g") 'grep)
(global-set-key (kbd "C-f r") 'rgrep)


;;;;;;;;;;
;; Emacs creates a backup only when you save the first time. This is
;; incompatible with most peoples basic editing behavior of leaving
;; Emacs and its buffers open all the time and constantly making
;; changes and writing them to disk.
;;
;; Emacs writes the backup before save-buffer and sets buffer-backed-up to t. To
;; enable further backups in this session, set buffer-backed-up to nil with this
;; hook.
(add-hook 'before-save-hook
          (lambda()
            (setq buffer-backed-up nil)))

;; Take care to customize `whitespace-style' in order to keep indentation of
;; source code.
(add-hook 'before-save-hook
          'whitespace-cleanup)



(defun my-sync-cursor-type-to-overwrite-mode ()
  "Change the `cursor-type' according to the overwrite or insert
mode. A horizontal bar indicates the overwrite mode."
  (if overwrite-mode
      (setq cursor-type 'hbar)
    (setq cursor-type 'box)))

;; Use hook `post-command-hook' to change cursor-type.
(add-hook 'post-command-hook 'my-sync-cursor-type-to-overwrite-mode)


;;;;;;;;;;
;; Spell checker support
(defcustom my-flyspell-prog-mode-list '(lisp-interaction-mode emacs-lisp-mode)
  "A list of major modes to select `flyspell-prog-mode' instead
  of `flyspell-mode' when `my-toggle-flyspell' is invoked."
  :type '(repeat :tag "major mode" symbol)
  :group 'my-customs)

(defun my-toggle-flyspell ()
  "Toggle flyspell mode with every call of this
function. flyspell mode will start in `flyspell-prog-mode' if the
actual `major-mode' matches an entry of
`my-flyspell-prog-mode-list'. Customize the list to your needs."
  (interactive)
  (if flyspell-mode
      (flyspell-mode 0)
    (if (memq (symbol-value 'major-mode) my-flyspell-prog-mode-list)
        (flyspell-prog-mode)
      (flyspell-mode 1))))

(global-set-key (kbd "C-b s") 'my-toggle-flyspell)



;;;;;;;;;;
;; Add support for some translation services or support to look-up a
;; specification.

(defcustom my-look-up-text-links
  '(("look-up-leo-dict" . ("http://dict.leo.org/ende?lp=ende&lang=de&search="))
    ("look-up-merriam-webster-thesaurus" . ("http://www.merriam-webster.com/thesaurus/"))
    ("look-up-linguee" .  ("http://www.linguee.de/deutsch-englisch/search?sourceoverride=none&source=auto&query="))
    ("look-up-python-org" . ("http://docs.python.org/search.html?q=")))
  "This alist defines the look-up services on the web. It is read
 by `my-look-up-text'. The alist has the following format:

 (MATCH . (HTTP-PROLOGUE &optional HTTP-EPILOGUE))

The complete URL string will be put together starting with the
 prologue, then the text and as an optional parameter the
 epilogue (if this is required for the complete URL)."
  :type '(repeat (cons
                  (string :tag "Matcher")
                  (set :tag "URL"
                       (string :tag "Prologue")
                       (string :tag "Epilogue"))))
  :group 'my-customs)

(defun my-look-up-text ()
  "Look up the current word or region on one of the web pages,
defined by `my-look-up-text-links'."
  (interactive)
  (let* ((to-suggest "look-up-leo-dict")
         (server-part-1 "")
         (server-part-2 "")
         (look-up-text nil)
         (to-lang (completing-read (format "Look up server (%s): " to-suggest)
                                   my-look-up-text-links nil t nil nil to-suggest)))
    (setq look-up-text (if (and transient-mark-mode mark-active)
                           (buffer-substring-no-properties (region-beginning) (region-end))
                         (thing-at-point 'word)))
    (if (arrayp look-up-text)
        (let* ((server-part-1 (cadr (assoc to-lang my-look-up-text-links)))
               (server-part-2 (cddr (assoc to-lang my-look-up-text-links))))
          (if (stringp server-part-2)
              (browse-url (concat server-part-1 (url-hexify-string look-up-text) server-part-2))
            (browse-url (concat server-part-1 (url-hexify-string look-up-text))))))))

(global-set-key (kbd "C-f l") 'my-look-up-text)


;;;;;;;
;; Support functions to make Emacs life easier.
(defun my-kill-ring-symbol-at-point()
  "This function adds the symbol-at-point to the kill ring if no
region is active. Otherwise, kill-ring-save will be called to
kill the content of the active region."
  (interactive)
  (if (not (and transient-mark-mode mark-active))
      (progn (let ((sym (thing-at-point 'symbol)))
               (when (stringp sym)
                 (kill-new sym))))
	(kill-ring-save (mark) (point))))

(global-set-key (kbd "M-w") 'my-kill-ring-symbol-at-point)



(defun my-revert-all-buffers ()
  "Reverts all opened buffers from their respective files. In
case the buffer is modofied, the buffer will not be reverted."
  (interactive)
  (let* ((mod-counter 0)
         (no-mod-counter 0))
	(dolist (buf (buffer-list))
      (when (buffer-file-name buf)
    	(if (buffer-modified-p buf)
            (setq mod-counter (1+ mod-counter))
          (save-excursion
            (set-buffer buf)
            (revert-buffer t t t)
            (setq no-mod-counter (1+ no-mod-counter))))))
	(if (> mod-counter 0)
        (message "%d buffer(s) reverted. %d modified buffer(s) not reverted."
                 no-mod-counter mod-counter)
      (message "%d buffer(s) reverted."
               no-mod-counter))))


(defun my-insert-date (prefix)
  "When called without prefix arg, it inserts at point the
current date and `user-mail-address' in change-log-mode
style. When called with any prefix arg, inserts at point the current date
plus time and `user-mail-address'."
  (interactive "P")
  (let* ((MOYlist '(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))
         (now (decode-time))
         (final-string (if (eq prefix nil)
                           (format "%04d-%02d-%02d "
                                   (nth 5 now) ; yyyy
                                   (nth 4 now)
                                   (nth 3 now))
                         (format "%04d-%s-%02d %02d:%02d "
                                 (nth 5 now) ; yyyy
                                 (nth (- (nth 4 now) 1) MOYlist)  ; month
                                 (nth 3 now) ; dd
                                 (nth 2 now) ; HH
                                 (nth 1 now))))) ; dd
    (insert (concat final-string "<" user-mail-address ">"))))

(global-set-key (kbd "C-b d") 'my-insert-date)



(defun my-where-is-point ()
  "Searches upwards, starting from point to find a string that
looks like a function. The matched function is displayed in the
minibuffer area. Works good for python an C."
  (interactive)
  (when (memq (symbol-value 'major-mode) '(c-mode c++-mode python-mode))
    (save-excursion
      (let* ((save-hl-line-mode hl-line-mode))
        (search-backward-regexp "^\\w+.*\\n* *[(){:]$" 0 t)
        (recenter nil)
        (hl-line-mode 1)
        (sit-for 1)
        (when (not save-hl-line-mode)
          (hl-line-mode -1))))
    (recenter nil))) ;; bring point to center of window

(global-set-key (kbd "C-f C-f") 'my-where-is-point)


;;;;;;;;;;;
;; Use the hippie way to expand
(eval-after-load "hippie-exp"
  '(setq hippie-expand-try-functions-list '(try-expand-dabbrev
                                            try-expand-dabbrev-all-buffers
                                            try-complete-lisp-symbol)))

(global-set-key (kbd "M-b") 'hippie-expand)
(global-set-key (kbd "C-<return>") 'hippie-expand)

;;;;;;;;;;
;; Fold the text. It works in any mode.
(defun my-toggle-selective-display (column)
  (interactive "P")
  (set-selective-display
   (if selective-display nil (or column 1))))

(global-set-key (kbd "C-b z") 'my-toggle-selective-display)

;;;;;;;;;
;; Load project specific functions
(require 'resource/dev-setup)

;;;;;;;
;; Load support for flymake-mode
(require 'resource/flymake)

;;;;;;;
;; Load my skeleton templates
(require 'resource/skeletons)

;;;;;;;
;; Load smart complete/indent functions
(require 'resource/smart-tab)

;;;;;;;;;
;; Browse files and symbols with ido-mode

(autoload 'my-ido-find-tag "resource/ido")
(autoload 'my-ido-find-file-in-tag-files "resource/ido")
(autoload 'my-ido-dired "resource/ido")

(global-set-key (kbd "C-f d") 'my-ido-dired)
(global-set-key (kbd "C-f f") 'my-ido-find-file-in-tag-files)
(global-set-key (kbd "C-f t") 'my-ido-find-tag)


;;;;;;;;;
;; Compile and build tags, based on desktop-dirname.
(add-hook 'desktop-after-read-hook
          (lambda ()
            (require 'resource/desktop)
            (global-set-key (kbd "C-b c") 'my-desktop-compiler)
            (global-set-key (kbd "C-b t") 'my-desktop-build-tags)
            (global-set-key (kbd "C-f a") 'my-desktop-grep)))


;;;;;;;;;;
;; Support for the great asciidoc tool. The associated mode can be found under
;; http://xpt.sourceforge.net/tools/doc-mode
(autoload 'asciidoc-mode "modes/asciidoc-mode")
(add-to-list 'auto-mode-alist '("\\.txt$" . asciidoc-mode))

;; Support for my favorite VCS
(add-to-list 'auto-mode-alist '("/bzr_log\\." . longlines-mode))

;; Use this hooks to change file mode.
(add-hook 'after-save-hook
          'executable-make-buffer-file-executable-if-script-p)

(add-hook 'minibuffer-setup-hook
          (lambda ()
            (setq truncate-lines nil)))

(add-hook 'python-mode-hook
          (lambda ()
            (local-set-key (kbd "<return>") 'newline-and-indent)
            (subword-mode 1)
            (setq python-indent 4)
            (whitespace-mode 1)
            (setq whitespace-style '(empty tabs trailing
                                           indentation::space
                                           space-before-tab::space
                                           space-after-tab::space))))


(add-hook 'emacs-lisp-mode-hook
          (lambda ()
            (local-set-key (kbd "<return>") 'newline-and-indent)
            (local-set-key (kbd "(") 'skeleton-pair-insert-maybe)
            (local-set-key (kbd "\"") 'skeleton-pair-insert-maybe)
            (eldoc-mode 1)))

(add-hook 'text-mode-hook
          (lambda ()
            (local-set-key [return] 'newline-and-indent)
            (text-mode-hook-identify)))


;; Stop ^M's from displaying in system shell window
(add-hook 'comint-output-filter-functions 'shell-strip-ctrl-m nil t)

(add-hook 'comint-mode-hook
          (lambda()
            (setq comint-process-echoes t))) ; This prevents shell commands from being echoed

(add-hook 'shell-mode-hook
          (lambda ()
            (setq comint-scroll-to-bottom-on-input t)
            (setq comint-scroll-to-bottom-on-output t)
            (setq comint-scroll-show-maximum-output t)
            (compilation-shell-minor-mode)))


(add-hook 'c-mode-common-hook
          (lambda ()
            (local-set-key (kbd "<return>") 'newline-and-indent)
            (local-set-key (kbd "M-<return>") 'c-indent-new-comment-line)
            (subword-mode 1)
            (my-doxygen-fontify-c-hook)
            (c-toggle-auto-newline -1)
            (c-toggle-hungry-state -1)
            (c-set-offset 'substatement-open '0)
            (c-set-offset 'inline-open '+)
            (c-set-offset 'block-open '+)
            (c-set-offset 'case-label '+)))

;; Indenting in C and tab behaviour. Optimized for a tab width of four.
(setq c-basic-offset 4
      tab-width  4
      indent-tabs-mode nil
      tab-stop-list '(4 8 12 16 20 24 28 32 36 40))

(setq c-font-lock-extra-types (quote ("uint8_t" "uint16_t" "uint32_t"
                                      "sint8_t" "sint16_t" "sint32_t"
                                      "bool_t")))

;; Set indentation style
(setq c-default-style '((c-mode . "k&r")
                        (other  . "k&r")))


(setq c-doc-comment-style (quote
                           ((c-mode . doxygen)
                            (java-mode . javadoc)
                            (pike-mode . autodoc))))

(defun my-doxygen-fontify-c-hook ()
  (interactive)
  (setq doxygen-font-lock-doc-comments
        (let ((symbol "[a-zA-Z0-9_]+")
              (header "^ \\* "))
          `((,(concat header "\\(" "[\\\\@]" symbol "\\)") 1 ,c-doc-markup-face-name prepend nil)
            (,(concat "[\\\\@]" symbol) 0 ,c-doc-markup-face-name prepend nil))))

  (setq doxygen-font-lock-keywords
        `((,(lambda (limit)
              (c-font-lock-doc-comments "/\\*[\\*!]" limit
                                        doxygen-font-lock-doc-comments))))))

;;;;;;;;;;
;; Mode VC needs filesets to work properly. Needed for operations on marked
;; files in a vc-dir buffer. Refer to chapter 22.18 of the Emacs manual.
(filesets-init)

;;;;;;;;;;
;; window move with shift plus cursor arrows
(windmove-default-keybindings)

;; winner-mode help to undo(C-c <left>) or redo (C-c <right> changes in the
;; window configuration.
(winner-mode 1)


;;;;;;;;;;
;; Some nice key mappings and supporting functions, that works quit well for me.

(global-set-key [C-kp-delete]       'kill-word)
(global-set-key [kp-delete]         'delete-char)
(global-set-key [end]               'move-end-of-line)
(global-set-key [home]              'move-beginning-of-line)
(global-set-key [f5]                'other-frame)
(global-set-key (kbd "M-DEL")       'join-line)
(global-set-key (kbd "C-b o")       'overwrite-mode)
(global-set-key (kbd "C-b =")       'diff-buffer-with-file)
(global-set-key (kbd "C-b j")       'webjump)
(global-set-key (kbd "C-b C-c")     'recompile)
(global-set-key (kbd "M-<down>")    'next-error)
(global-set-key (kbd "M-<up>")      'previous-error)

(global-set-key (kbd "C-S-<SPC>") (lambda ()
                                    (interactive)
                                    (set-mark-command (beginning-of-line))
                                    (forward-line 1)))

;; Two bindings to scroll the view port
(global-set-key (kbd "C-M-<up>") (lambda()
                                   (interactive)
                                   (scroll-down 1)))

(global-set-key (kbd "C-M-<down>") (lambda()
                                     (interactive)
                                     (scroll-up 1)))

(global-set-key (kbd "C-M-,") (lambda()
                                (interactive)
                                (tags-search (thing-at-point 'symbol))))


;;;;;;;;;;
;; Set propertie values.
;; Enable uppercase (C-x C-u) or lowercase (C-x C-l) conversions
(put 'downcase-region 'disabled nil)
(put 'upcase-region 'disabled nil)
;; Enable goal-column. Can be used by C-x C-n and left by C-u C-x C-n
(put 'set-goal-column 'disabled nil)
